home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / EXPIRE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-07  |  9.7 KB  |  380 lines

  1. /* Expire old messages.
  2.  * Inspired by 'expire.c' by Bernie Roehl.
  3.  * Substantially rewritten for integration into KA9Q NOS,
  4.  * WG7J v1.01 and later
  5.  * by Johan. K. Reinalda, WG7J/PA3DIS, March/April 92
  6.  *
  7.  * Old bid expiry by WG7J, March 92
  8.  */
  9. /* 'expire n' sets the expire interval for n hours.
  10.  * Each time the timer goes off, a new process is started,
  11.  * that expires the old messages...
  12.  *
  13.  * The control file '~/spool/expire.dat' contains lists of
  14.  * filename age
  15.  *
  16.  * where 'filename' is the name of the .txt file under '~/spool/mail'
  17.  * containing the messages (without the .txt extension)
  18.  * filename can be extended into subdirectories, and can have either
  19.  * '/', '\' or '.' to indicate subdirectories.
  20.  *
  21.  * 'age' is an integer giving the maximum age of a message in days,
  22.  * after which expiry is performed.
  23.  * If no age is given, the default age is 21 days.
  24.  *
  25.  */
  26. #include "global.h"
  27. #include "commands.h"
  28. #include "files.h"
  29. #ifdef MSDOS
  30. #include <dir.h>
  31. #include <dos.h>
  32. #else
  33. #include "ctype.h"
  34. #include <time.h>
  35. #include <sys/stat.h>
  36. #endif
  37. #include "timer.h"
  38. #include "proc.h"
  39. #include "bm.h"
  40. #include "delegate.h"
  41.  
  42. #if !defined(_lint)
  43. static char rcsid[] OPTIONAL = "$Id: expire.c,v 1.27 1997/09/07 21:18:28 root Exp root $";
  44. #endif
  45.  
  46. int ExpireActive = 0;
  47. char *ExpireArea = NULLCHAR;
  48. time_t ExpireLast = 0;
  49. extern char *nntp_name_expansion (char *name);
  50. extern void updateCtl (const char *who, struct let * info);
  51. extern int expired;
  52.  
  53.  
  54. static time_t j_mktime (struct tm *);
  55.  
  56. /* If you're using BC++ 2.0 or higher, you don't need this,
  57.  * but TCC 2.0 doesn't have it...
  58.  */
  59. /* Simple emulation of the mktime() call (sort-of works :-) )
  60.  * doesn't do any error checking,
  61.  * no timezone adjustments or value adjustments
  62.  * neglects seconds,
  63.  * and might be off by a day for leap year corrections
  64.  * Simply 'sort-a' calculates the number of seconds since 1970 - WG7J
  65.  */
  66. time_t
  67. j_mktime (t)
  68. struct tm *t;
  69. {
  70.     static int total[12] =
  71.     {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  72.     int years;
  73.     int leapyears;
  74.     int days;
  75.  
  76.     /* time count start at jan 1, 1970, 00:00 hrs */
  77.     years = t->tm_year - 70;
  78.     /* adjust in case year was passed in as 19xx, instead of xx */
  79.     if (years >= 1900)
  80.         years -= 1900;
  81.     /* adjust for leap-years */
  82.     leapyears = (years + 2) / 4;
  83.     if (!((years + 70) & 3) && (t->tm_mon < 2))
  84.         --leapyears;
  85.  
  86. #ifdef linux
  87.     days = years * 365L + leapyears + total[t->tm_mon] + (t->tm_mday - 1);
  88.     return (days * 86400L + t->tm_hour * 3600L + t->tm_min * 60L + t->tm_sec);
  89. #else
  90.     days = years * 365L + leapyears + total[t->tm_mon] + t->tm_mday;
  91.     return (days * 86400L + t->tm_hour * 3600L + t->tm_min * 60L - 19 * 3600L);
  92. #endif
  93. }
  94.  
  95.  
  96.  
  97. #if (defined(EXPIRY) || defined(DELEGATE))
  98.  
  99. /* Default expiry values: */
  100. #define DEFAULT_AGE 21        /* 21 days from arrival date */
  101. #define MSPHOUR (1000L*60L*60L)
  102. static struct timer Expiretimer;
  103. extern int PruneAge;
  104.  
  105. static void Expireprocess (int a, void *v1, void *v2);
  106. void Expiretick (void *);
  107. void expire (char *, int);
  108.  
  109.  
  110. int
  111. doexpire (int argc, char **argv, void *p OPTIONAL)
  112. {
  113.     if (argc < 2) {
  114.         tprintf ("timer: %lu/%lu hrs\n", read_timer (&Expiretimer) / MSPHOUR,
  115.             dur_timer (&Expiretimer) / MSPHOUR);
  116.         return 0;
  117.     }
  118.     if (*argv[1] == 'n') {
  119.         Expiretick (NULL);
  120.         return 0;
  121.     }
  122.     /* set the timer */
  123.     stop_timer (&Expiretimer);    /* Just in case */
  124.     Expiretimer.func = (void (*)(void *)) Expiretick;    /* what to call on timeout */
  125.     Expiretimer.arg = NULL;    /* dummy value */
  126.     set_timer (&Expiretimer, atol (argv[1]) * MSPHOUR);    /* set timer duration */
  127.     start_detached_timer (&Expiretimer);
  128.     return 0;
  129. }
  130.  
  131.  
  132.  
  133. void
  134. Expiretick (void *p OPTIONAL)
  135. {
  136.     start_detached_timer (&Expiretimer);
  137.     /* Spawn off the process */
  138.     if (!ExpireActive)
  139.         if (newproc ("Expiry", 2048, Expireprocess, 0, NULL, NULL, 0) == NULLPROC)
  140.             log (-1, "Couldn't start Expiration process");
  141. }
  142.  
  143.  
  144.  
  145. static void
  146. Expireprocess (int a OPTIONAL, void *v1 OPTIONAL, void *v2 OPTIONAL)
  147. {
  148. char line[80];
  149. int age = DEFAULT_AGE;
  150. char *cp;
  151. FILE *ctl;
  152.  
  153.     ExpireActive = 1;
  154.     log (-1, "EXPIRE process started");
  155. #ifdef DELEGATE
  156.     purge_delegate ();
  157. #endif
  158.     setMaintenance ();
  159.     if ((ctl = fopen (Expirefile, "r")) != NULLFILE) {
  160.         (void) time (&ExpireLast);
  161.         /* read lines from the control file */
  162.         while (fgets (line, sizeof (line), ctl) != NULLCHAR) {
  163.             kwait (NULL);    /* be nice */
  164.             if ((*line == '#') || (*line == '\n'))    /* comment or blank line */
  165.                 continue;
  166.             rip (line);
  167.             age = DEFAULT_AGE;
  168.             /* terminate area name */
  169.             if ((cp = strpbrk (line, " \t")) != NULLCHAR) {
  170.                 /* there is age info */
  171.                 *cp++ = '\0';
  172.                 age = atoi (cp);
  173.                 if (age <= 0)
  174.                     age = DEFAULT_AGE;
  175.             }
  176.             kwait (NULL);    /* be nice */
  177.             ExpireArea = line;    /*lint !e789 */
  178.             (void) nntp_name_expansion (line);
  179.             expire (line, age);
  180.             ExpireArea = NULLCHAR;
  181.         }
  182.         (void) fclose (ctl);
  183.     }
  184.     clearMaintenance ();
  185.     log (-1, "EXPIRE process completed");
  186.     ExpireActive = 0;
  187. }
  188.  
  189.  
  190.  
  191. void
  192. expire (char *filename, int age)
  193. {
  194. char file[128], bckfile[128], bckctl[128], *cp;
  195. char buf[128];
  196. int keep, copy, kept = 0;
  197. FILE *old;
  198. FILE *new;
  199. long pos;
  200. time_t now;
  201. time_t then;
  202. struct tm t;
  203. struct let lt;
  204. int entrynum = 1;
  205. int ctlfound = 0;
  206.  
  207.     if (age == -1)
  208.         age = PruneAge;
  209.     /* first replace all '.' and '\' with '/' */
  210.     for (cp = filename; *cp != '\0'; cp++)
  211.         if ((*cp == '.') || (*cp == '\\'))
  212.             *cp = '/';
  213.  
  214.     if (mlock (Mailspool, filename)) {
  215.         /* can't get a lock */
  216.         return;
  217.     }
  218.     /* rename the old *.ctl file */
  219.     sprintf (file, "%s/control/%s.ctl", Mailspool, filename);
  220.     sprintf (bckctl, "%s/control/%s.exp", Mailspool, filename);
  221.     unlink (bckctl);
  222.     if (rename (file, bckctl) != -1)
  223.         ctlfound = 1;
  224.  
  225.     /* now append the 'home dir' in front of name */
  226.     sprintf (file, "%s/%s", Mailspool, filename);
  227.  
  228.     /* get the name for the backup file */
  229.     sprintf (bckfile, "%s.exp", file);
  230.     strcat (file, ".txt");
  231.  
  232.     /* rename the file */
  233.     unlink (bckfile);
  234.     if (rename (file, bckfile) == -1) {
  235.         rmlock (Mailspool, filename);
  236.         return;
  237.     }
  238.     kwait (NULL);
  239.     /* open the backup file and the new txt file */
  240.     if ((old = fopen (bckfile, READ_TEXT)) == NULLFILE) {
  241.         rmlock (Mailspool, filename);
  242.         return;
  243.     }
  244.     if (!ctlfound && filelength(fileno(old)) == 0)    {
  245.         (void) fclose (old);
  246.         unlink (bckfile);
  247.         rmlock (Mailspool, filename);
  248.         log (-1, "Expire: removing empty file for area %s", filename);
  249.         return;
  250.     }
  251.     if ((new = fopen (file, WRITE_TEXT)) == NULLFILE) {
  252.         rmlock (Mailspool, filename);
  253.         return;
  254.     }
  255.     kwait (NULL);
  256.     (void) time (&now);
  257.     copy = expired = 0;
  258.     pos = ftell (old);
  259.     while (fgets (buf, sizeof (buf), old) != NULLCHAR) {
  260.         kwait (NULL);
  261.         if (!strncmp (buf, "From ", 5)) {
  262.             /* start of next message; at this point
  263.              * pos has the offset of the start of this line
  264.              */
  265.             keep = copy = 0;
  266.             while (fgets (buf, sizeof (buf), old) != NULLCHAR) {
  267.                 kwait (NULL);
  268.                 if (*buf == '\n')
  269.                     break;    /* end of headers */
  270.                 if (htype (buf) == DATE) {
  271.                     /* find age from ARPA style date */
  272.                     /* check to see if there is a "Day, " field */
  273.                     if ((cp = strchr (buf, ',')) != NULLCHAR) {
  274.                         /* probably standard ARPA style header */
  275.                         cp = &buf[11];    /* get past header and DAY field */
  276.                     } else {
  277.                         /* probably a NNTP style message, that has no
  278.                          * "Day, " part in the date line
  279.                          */
  280.                         cp = &buf[6];
  281.                     }
  282.                     /* now we should be at the start of the
  283.                      * "14 Apr 92 08:14:32" string
  284.                      */
  285.                     if (strlen (cp) < 17)    /* Too short */
  286.                         break;
  287.                     t.tm_mday = atoi (cp);
  288.                     if (*(++cp) != ' ')
  289.                         ++cp;
  290.                     ++cp;
  291.                     for (t.tm_mon = 0; t.tm_mon < 12; t.tm_mon++)
  292.                         if (strnicmp (Months[t.tm_mon], cp, 3) == 0)
  293.                             break;
  294.                     if (t.tm_mon == 12)
  295.                         break;    /* invalid */
  296. #if 1
  297.                     /* modified to accept either
  298.                      * "14 Apr 92 08:14:32" string or
  299.                      * "14 Apr 1992 08:14:32" string
  300.                      * WA3DSP 11/94 - modified by KO4KS
  301.                      */
  302.  
  303.                     while (*cp != ' ')
  304.                         ++cp;
  305.                     ++cp;
  306.                     t.tm_year = atoi (cp);
  307.                     if (t.tm_year > 99)
  308.                         t.tm_year %= 100;
  309.  
  310.                     while (*cp != ' ')
  311.                         ++cp;
  312.                     ++cp;
  313.                     t.tm_hour = atoi (cp);
  314.                     t.tm_min = atoi (cp + 3);
  315.                     t.tm_sec = atoi (cp + 6);
  316.  
  317. #else
  318.                     t.tm_year = atoi (cp + 4);
  319.                     t.tm_hour = atoi (cp + 7);
  320.                     t.tm_min = atoi (cp + 10);
  321.                     t.tm_sec = atoi (cp + 13);
  322. #endif
  323.                     if ((then = j_mktime (&t)) == (time_t) -1)
  324.                         break;    /* invalid, delete */
  325.                     /* Now check against age */
  326.                     if (now - then < (time_t) (age * 86400L))
  327.                         keep = 1;
  328.                     break;
  329.                 }
  330.             }
  331.             statusCtl (filename, "exp", <, entrynum, 1);
  332.             if (!keep && (lt.status & BM_PERMANENT))
  333.                 keep = 1;    /* don't expire permanent messages */
  334.             if (keep) {
  335.                 /* rewind to start of this message,
  336.                  * write from-line and copy the rest
  337.                  */
  338.                 kwait (NULL);
  339.                 if (lt.status & BM_DELETE)
  340.                     expired++;
  341.                 else {
  342.                     lt.start = ftell (new);
  343.                     updateCtl (filename, <);
  344.                     fseek (old, pos, SEEK_SET);
  345.                     (void) fgets (buf, sizeof (buf), old);
  346.                     fputs (buf, new);
  347.                     copy = 1;
  348.                     kept++;
  349.                 }
  350.             } else
  351.                 expired++;
  352.             entrynum++;
  353.         } else {    /* Any none 'from' line */
  354.             if (copy)
  355.                 /* we're in the middle of copying a message */
  356.                 fputs (buf, new);
  357.         }
  358.         kwait (NULL);
  359.         pos = ftell (old);
  360.     }
  361.     (void) fclose (old);
  362.     (void) fclose (new);
  363.     kwait (NULL);
  364.     unlink (bckfile);
  365.     unlink (bckctl);
  366.     rmlock (Mailspool, filename);
  367.     if (expired)
  368.         log (-1, "Expired: %d in %s", expired, filename);
  369.  
  370.  
  371.     if (!kept)    {
  372.         log (-1, "Expire: removing empty file for area %s", filename);
  373.         sprintf (file, "%s/%s.txt", Mailspool, filename);
  374.         unlink (file);
  375.     }
  376. }
  377.  
  378.  
  379. #endif /* EXPIRY */
  380.